﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ScottGarland;

namespace AOChat
{
    class phpMath
    {
        public static BigInteger bighexdec(string x)
        {
            const int base_ = 16; 
            if (x.Substring(0, 2) != "0x")
            {

                return new BigInteger(x, base_);
            }
            else
            {
                return new BigInteger(x.Substring(2), base_);
            }
            //BigInteger r = 0;
            //BigInteger hex_base = 16;
            //int p;

            //int idx = 0;
            //for (p = x.Length - 1; p >= 0; p--)
            //{
            //    char hex = x[idx];
            //    uint digVal =hexdec(hex);
            //    BigInteger b = 1;
            //    for (int i = 1; i <= p; i++)
            //    {
            //        b = b * hex_base; //no power yet supported so
            //    }
            //    r = r + digVal * b;
            //    idx++;
            //}
            ////for (p = q = x.Length - 1; p >= 2; p--)
            ////{
            ////    //r = bcadd(r, bcmul(hexdec(x[p]), bcpow(16, q-p)));
            ////    BigInteger b = hex_base ^ (q - p);
            ////    r = r + (hexdec(x[p]) * b);
            ////}
            //return r;
        }

    //http://www.php.net/manual/en/function.hexdec.php

public static BigInteger bchexdec(string hex)
{
    //int len = hex.Length;
    //BigInteger dec = new BigInteger(0);
    //BigInteger b = new BigInteger(16);
    //for (int i = 1; i <= len; i++)
    //    dec = dec + hexdec(hex[i - 1]) * b ^ (len - i);
    
    //return dec;
    return new BigInteger(hex, 16);
}

public static uint hexdec(char p)
{
    switch (p)
    {
        case '0': return 0;
        case '1': return 1;
        case '2': return 2;
        case '3': return 3;
        case '4': return 4;
        case '5': return 5;
        case '6': return 6;
        case '7': return 7;
        case '8': return 8;
        case '9': return 9;
        case 'a':
        case 'A': return 10;
        case 'b':
        case 'B': return 11;
        case 'c':
        case 'C': return 12;
        case 'd':
        case 'D': return 13;
        case 'e':
        case 'E': return 14;
        case 'f':
        case 'F': return 15;
        default: throw new Exception("Not a valid hexidecimal digit: " + p);
    }
}

public static BigInteger hexdec(string hex)
{
    return new BigInteger(hex, 16);
    //BigInteger dec = 0;
    //BigInteger e = 1;

    //for (int i = hex.Length - 1; i >= 0; e = e * 16)
    //{
    //    BigInteger factor = hexdec(hex[i]);
    //    dec = dec + factor * e;
    //    i--;
    //}

    //return dec;
    //throw new Exception("Function not yet tested.");
} 

        //public static object bcpow(int p,int p_2)
        //{


        //////////public static string bigdechex(int x)
        //////////{
        //////////    r = "";
        //////////    while (x != "0")
        //////////    {
        //////////        r = dechex(bcmod(x, 16));
        //////////        x = bcdiv(x, 16);
        //////////    }
        //////////    return r;
        //////////}

        public static string bigdechex(BigInteger x)
        {
            //string r = "";
            //while (x != 0)
            //{
            //    BigInteger b = x;
            //    BigInteger exp = 16;
            //    r = (b % exp).ToString(16) + r;
            //    x = x / 16;
            //}

            //return r;
            return x.ToString(16);
        }
        public static int big_cmp(BigInteger value, BigInteger bit)
        {
            return (value == bit) ? 0 : (value > bit ? 1 : -1);
        }

        public static int big_cmp(long lval, long rval)
        {
            return (lval == rval) ? 0 : (lval > rval ? 1 : -1);
        }
        public static int big_cmp(int lval, int rval)
        {
            return (lval == rval) ? 0 : (lval > rval ? 1 : -1);
        }


//string strbin2hex(string bin)
//{
//  int last = bin.Length-1;
//  string x = "";
//  for(int i=0; i<=last; i++){ x += $bin[$last-$i] * pow(2,$i); }
//  return dechex($x);
//}
//http://php.net/manual/en/function.bin2hex.php
//Regarding the fabled hex2bin, the easiest way I've found to "replace" it is the following call to function pack(): 

//<?php 
//$bin_str = pack("H*" , $hex_str);    
//?> 

        ////See http://php.net/manual/en/function.bin2hex.php
        //public static string hex2bin(string str)
        //{
        //    //old code
        //    //string bin = "";
        //    //int i = 0;
        //    //do
        //    //{
        //    //    string twoChars = str[i].ToString() + str[i + 1].ToString();
        //    //    int represent = int.Parse(hexdec(twoChars).ToString());
        //    //    bin = bin + Convert.ToChar(represent);

        //    //    i += 2;
        //    //} while (i < str.Length);
        //    //return bin;
        //    //end old code

        //}

        /*
function my_bcmod( $x, $y ) 
{ 
    // how many numbers to take at once? carefull not to exceed (int) 
    $take = 5;     
    $mod = ''; 

    do 
    { 
        $a = (int)$mod.substr( $x, 0, $take ); 
        $x = substr( $x, $take ); 
        $mod = $a % $y;    
    } 
    while ( strlen($x) ); 

    return (int)$mod; 
}   */

        /*http://php.net/manual/en/function.bcmod.php
         * Versions of PHP prior to 5 do not have bcpowmod in their repertoire.  This routine simulates this function using bcdiv, bcmod and bcmul.  It is useful to have bcpowmod available because it is commonly used to implement the RSA algorithm.
        The function bcpowmod(v, e, m) is supposedly equivalent to bcmod(bcpow(v, e), m).  However, for the large numbers used as keys in the RSA algorithm, the bcpow function generates a number so big as to overflow it.  For any exponent greater than a few tens of thousands, bcpow overflows and returns 1.
        This routine will iterate through a loop squaring the result, modulo the modulus, for every one-bit in the exponent.  The exponent is shifted right by one bit for each iteration.  When it has been reduced to zero, the calculation ends.
        This method may be slower than bcpowmod but at least it works.

        function PowModSim($Value, $Exponent, $Modulus)
          {
          // Check if simulation is even necessary.
          if (function_exists("bcpowmod"))
            return (bcpowmod($Value, $Exponent, $Modulus));

          // Loop until the exponent is reduced to zero.
          $Result = "1";

          while (TRUE)
            {
            if (bcmod($Exponent, 2) == "1")
              $Result = bcmod(bcmul($Result, $Value), $Modulus);

            if (($Exponent = bcdiv($Exponent, 2)) == "0") break;

            $Value = bcmod(bcmul($Value, $Value), $Modulus);
            }

          return ($Result);
          } */



        public static BigInteger powmod(BigInteger Value, BigInteger Exponent, BigInteger Modulus)
        {
            BigInteger test = new BigInteger();

            // Loop until the exponent is reduced to zero.
            BigInteger Result = new BigInteger(1);
            BigInteger two = new BigInteger(2);
            BigInteger one = new BigInteger(1);
            while (true)
            {
                BigInteger mod = Exponent % two;
                if (mod == one)
                {
                    Result = (Result * Value) % Modulus;
                }
                Exponent = Exponent / two;
                if (Exponent == 0) break;
                Value = (Value * Value) % Modulus;
            }

            return (Result);
        }

        //function bcmath_powm($base, $exp, $mod)
        //{
        //    $base = $this->bighexdec($base);
        //    $exp  = $this->bighexdec($exp);
        //    $mod  = $this->bighexdec($mod);

        //    if(function_exists("bcpowmod")) /* PHP5 finally has this */
        //    {
        //        $r = bcpowmod($base, $exp, $mod);
        //        return $this->bigdechex($r);
        //    }

        //    $r = 1;
        //    $p = $base;

        //    while(true)
        //    {
        //        if(bcmod($exp, 2))
        //        {
        //            $r = bcmod(bcmul($p, $r), $mod);
        //            $exp = bcsub($exp, "1");
        //            if(bccomp($exp, "0") == 0)
        //            {
        //                return $this->bigdechex($r);
        //            }
        //        }

        //        $exp = bcdiv($exp, 2);
        //        $p = bcmod(bcmul($p, $p), $mod);
        //    }
        //}

        /*Just that $power cannot have decimal digits in it. http://www.php.net/manual/en/function.bcpow.php
         * 
        function bcpow_($num, $power) {
            $awnser = "1";
            while ($power) {
                $awnser = bcmul($awnser, $num, 100);
                $power = bcsub($power, "1");
            }
            return rtrim($awnser, '0.');
        }*/

        //string bcpow_(string num, string power) {
        //    awnser = "1";
        //    while (power) {
        //        awnser = bcmul(awnser, num, 100);
        //        power = bcsub(power, "1");
        //    }
        //    return rtrim($awnser, '0.');
        //}

        ////public static double powm(string base_, string exp, string mod)
        ////{


            //////double dbase = bighexdec(base_);
            //////double dexp = bighexdec(exp);
            //////double dmod = bighexdec(mod);
            //////double b = dbase;
            //////double p = dexp;
            //////double m = dmod;
            //////double r = Math.Pow(b, p) % m;
            //////return r;

            //$a = bcpowmod($x, $y, $mod);
            //equivalent to
            //$b = bcmod(bcpow($x, $y), $mod);



            //    if(function_exists("bcpowmod")) /* PHP5 finally has this */
            //    {
            //        r = bcpowmod(sbase, exp, mod);
            //        return this.bigdechex(r);
            //    }

            ////string r = "1";
            ////string p = base_;

            ////while(true)
            ////{
            ////    if( exp % 2 > 0)
            ////    {
            ////        //r = bcmod(bcmul(p, r), mod);
            ////        r = bcmod(bcmul(p,r) , mod);
            ////        exp = bcsub(exp, 1);
            ////        if(bccomp(exp, "0") == 0)
            ////        {
            ////            return bigdechex(r);
            ////        }
            ////    }

            ////    exp = bcdiv(exp, 2);
            ////    p = bcmod(bcmul(p, p), mod);
            ////}
        ////}

        //public static string bcdiv(string exp, double p)
        //{
        //    return (double.Parse(exp) / p).ToString();
        //}

        //public static string bigdechex(string r)
        //{
        //    return bigdechex(double.Parse(r));
        //}


        //public static string bcmul(string p, string r)
        //{
        //    double result = double.Parse(p) * double.Parse(r);
        //    if (result == double.NaN || double.IsInfinity(result))
        //        throw new Exception("bcmul functio failed...Overflow exception.");
        //    return result.ToString();

        //}

        //public static string bcsub(string p1, double p2)
        //{
        //    return (double.Parse(p1) - p2).ToString();
        //}

        //public static string bcmod(string p, string mod)
        //{
        //    //return (int.Parse(p) % int.Parse(mod)).ToString();
        //    return my_bcmod(p, double.Parse(mod)).ToString();
        //}

        ////public static int my_bcmod(string x, double y)
        ////{
        ////    int take = 5;
        ////    int mod = 0;
        ////    double dx = double.Parse(x);
        ////    do
        ////    {
        ////        string a = mod.ToString() + x.Substring(0, take);
        ////        x = x.Substring(take);

        ////        mod = (int)(dx % y);
        ////    } while (x.Length > 0);

        ////    return mod;
        ////}

        //public static string bcmod_string(string p, string mod)
        //{
        //    //return (int.Parse(p) % int.Parse(mod)).ToString();
        //    return my_bcmod(p, double.Parse(mod)).ToString();
        //}
    }
}
